import React from 'react';
import * as THREE from 'three';
// import { GLTFLoader } from '../../libs/GLTFLoader';
import { img2matrix, randnum } from '../../libs/Utils';
import CANNON from 'cannon';
import CannonHelper from '../../libs/CannonHelper';
import JoyStick from './components/joyStick';
// import foxModel from './models/Fox.glb';
// import Shelter from './models/Shelter.glb';
import heightMapImage from '../../assets/Heightmap.png';
// import snowflakeTexture from './images/snowflake.png';
// import Stats from "three/examples/jsm/libs/stats.module";
import styles from './index.module.less';

export default class Room extends React.Component {
  scene: any;
  camera: any;
  player: any;
  target: any;
  canvasRef: any;
  playPosition = { x: 0, y: -.05, z: 0 };
  shelterPosition = { x: 93, y: -2, z: 25.5 };
  renderer: any;
  setup = { forward: 0, turn: 0 };
  constructor(props: {} | Readonly<{}>) {
    super(props);
  }

  state = {
    loadingProcess: 100,
    showLoading: true,
    freeDiscover: false
  }

  componentDidMount() {
    this.initThree();
    this.addEvent();
  }

  addEvent = () => {
    window.addEventListener('resize', () => {
      var width = window.innerWidth;
      var height = window.innerHeight;
      this.renderer.setSize(width, height);
      this.camera.aspect = width / height;
      this.camera.updateProjectionMatrix();
    }, false);
  }

  initThree = () => {
    const renderer = new THREE.WebGLRenderer({
      canvas: this.canvasRef,
      antialias: true,
      alpha: true
    });
    this.renderer = renderer;
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    const scene = new THREE.Scene();
    this.scene = scene;
    const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, .01, 100000);
    camera.position.set(1, 1, -1);
    this.camera = camera;
    camera.lookAt(scene.position);

    // 添加灯光
    const ambientLight = new THREE.AmbientLight(0xffffff, .4);
    scene.add(ambientLight);

    // cannon
    const cannonHelper = new CannonHelper(scene);
    const world = new CANNON.World();
    world.broadphase = new CANNON.SAPBroadphase(world);
    world.gravity.set(0, -10, 0);
    world.defaultContactMaterial.friction = 0;
    const groundMaterial = new CANNON.Material("groundMaterial");
    const wheelMaterial = new CANNON.Material("wheelMaterial");
    const wheelGroundContactMaterial = new CANNON.ContactMaterial(wheelMaterial, groundMaterial, {
      friction: 0,
      restitution: 0,
      contactEquationStiffness: 1000
    });
    // 给世界添加 contactMaterial
    world.addContactMaterial(wheelGroundContactMaterial);

    // 添加 front & back 光源
    var light = new THREE.DirectionalLight(0xffffff, 1);
    light.position.set(1, 1, 1).normalize();
    scene.add(light);

    // 星空粒子
    // const textureLoader = new THREE.TextureLoader();
    // const imageSrc = textureLoader.load(snowflakeTexture);
    // const shaderPoint = THREE.ShaderLib.points;
    // const uniforms = THREE.UniformsUtils.clone(shaderPoint.uniforms);
    // uniforms.map.value = imageSrc;
    // var sparkGeometry = new THREE.Geometry();
    // for (let i = 0; i < 1000; i++) {
    //   sparkGeometry.vertices.push(new THREE.Vector3());
    // }
    // const sparks = new THREE.Points(sparkGeometry, new THREE.PointsMaterial({
    //   size: 2,
    //   color: new THREE.Color(0xffffff),
    //   map: uniforms.map.value,
    //   blending: THREE.AdditiveBlending,
    //   depthWrite: false,
    //   transparent: true,
    //   opacity: 0.75
    // }));
    // sparks.scale.set(1, 1, 1);
    // scene.add(sparks);
    // sparks.geometry.vertices.map(spark => {
    //   spark.y = randnum(30, 40);
    //   spark.x = randnum(-500, 500);
    //   spark.z = randnum(-500, 500);
    //   return true;
    // });

    // target
    var geometry = new THREE.BoxGeometry(.5, 1, .5);
    geometry.applyMatrix4(new THREE.Matrix4().makeTranslation(0, .5, 0));
    const target = new THREE.Mesh(geometry, new THREE.MeshNormalMaterial({
      transparent: true,
      opacity: 0
    }));
    scene.add(target);

    var directionalLight = new THREE.DirectionalLight(new THREE.Color(0xffffff), .5);
    directionalLight.position.set(0, 1, 0);
    directionalLight.castShadow = true;
    directionalLight.target = target;
    target.add(directionalLight);

    // 添加地形
    var sizeX = 128, sizeY = 128, minHeight = 0, maxHeight = 60, check: any = null;
    Promise.all([
      img2matrix.fromUrl(heightMapImage, sizeX, sizeY, minHeight, maxHeight)(),
    ]).then(function (data) {
      var matrix = data[0] as number[];
      const terrainShape = new CANNON.Heightfield(matrix, { elementSize: 10 });
      const terrainBody = new CANNON.Body({ mass: 0 });
      terrainBody.addShape(terrainShape);
      terrainBody.position.set(-sizeX * terrainShape.elementSize / 2, -10, sizeY * terrainShape.elementSize / 2);
      terrainBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2);
      world.add(terrainBody);
      cannonHelper.addVisual(terrainBody, 'landscape');
      var raycastHelperGeometry = new THREE.CylinderGeometry(0, 1, 5, 1.5);
      raycastHelperGeometry.translate(0, 0, 0);
      raycastHelperGeometry.rotateX(Math.PI / 2);
      var raycastHelperMesh = new THREE.Mesh(raycastHelperGeometry, new THREE.MeshNormalMaterial());
      scene.add(raycastHelperMesh);
      check = () => {
        var raycaster = new THREE.Raycaster(target.position, new THREE.Vector3(0, -1, 0));
        var intersects = raycaster.intersectObject(terrainBody.threemesh.children[0]);
        if (intersects.length > 0) {
          raycastHelperMesh.position.set(0, 0, 0);
          raycastHelperMesh.lookAt(intersects[0].face.normal);
          raycastHelperMesh.position.copy(intersects[0].point);
        }
        // 将模型放置在地形上
        target.position.y = intersects && intersects[0] ? intersects[0].point.y + 0.1 : 30;
        // 标志基地
        // var raycaster2 = new THREE.Raycaster(shelterLocation.position, new THREE.Vector3(0, -1, 0));
        // var intersects2 = raycaster2.intersectObject(terrainBody.threemesh.children[0]);
        // shelterLocation.position.y = intersects2 && intersects2[0] ? intersects2[0].point.y + .5 : 30;
        // shelterLight.position.y = shelterLocation.position.y + 50;
        // shelterLight.position.x = shelterLocation.position.x + 5
        // shelterLight.position.z = shelterLocation.position.z;
      }
    });

    // 模型加载进度管理
    // const loadingManager = new THREE.LoadingManager();
    // loadingManager.onProgress = async(url, loaded, total) => {
    //   if (Math.floor(loaded / total * 100) === 100) {
    //     this.loadingProcessTimeout && clearTimeout(this.loadingProcessTimeout);
    //     this.loadingProcessTimeout = setTimeout(() => {
    //       this.setState({ loadingProcess: Math.floor(loaded / total * 100) });
    //     }, 800);
    //   } else {
    //     this.setState({ loadingProcess: Math.floor(loaded / total * 100) });
    //   }
    // };
    this.target = target;

    // 添加狐狸模型
    // var mixers = [], clip1, clip2;
    // const gltfLoader = new GLTFLoader(loadingManager);
    // gltfLoader.load(foxModel, mesh => {
    //   mesh.scene.traverse(child => {
    //     if (child.isMesh) {
    //       child.castShadow = true;
    //       child.material.side = THREE.DoubleSide;
    //     }
    //   });
    //   var player = mesh.scene;
    //   player.position.set(this.playPosition.x, this.playPosition.y, this.playPosition.z);
    //   player.scale.set(.008, .008, .008);
    //   target.add(player);
    //   this.target = target;
    //   this.player = player;
    //   var mixer = new THREE.AnimationMixer(player);
    //   clip1 = mixer.clipAction(mesh.animations[0]);
    //   clip2 = mixer.clipAction(mesh.animations[1]);
    //   clip2.timeScale = 1.6;
    //   mixers.push(mixer);
    // });

    // 基地
    // const shelterGeometry = new THREE.BoxBufferGeometry(0.15, 2, 0.15);
    // shelterGeometry.applyMatrix4(new THREE.Matrix4().makeTranslation(0, 1, 0));
    // const shelterLocation = new THREE.Mesh(shelterGeometry, new THREE.MeshNormalMaterial({
    //   transparent: true,
    //   opacity: 0
    // }));
    // shelterLocation.position.set(this.shelterPosition.x, this.shelterPosition.y, this.shelterPosition.z);
    // shelterLocation.rotateY(Math.PI);
    // scene.add(shelterLocation);

    // // 基地模型
    // gltfLoader.load(Shelter, mesh => {
    //   mesh.scene.traverse(child => {
    //     child.castShadow = true;
    //   });
    //   mesh.scene.scale.set(5, 5, 5);
    //   mesh.scene.position.y = -.5;
    //   shelterLocation.add(mesh.scene)
    // });

    // // 基地点光源
    // var shelterPointLight = new THREE.PointLight(0x1089ff, 2);
    // shelterPointLight.position.set(0, 0, 0);
    // shelterLocation.add(shelterPointLight);
    // var shelterLight = new THREE.DirectionalLight(0xffffff, 0);
    // shelterLight.position.set(0, 0, 0);
    // shelterLight.castShadow = true;
    // shelterLight.target = shelterLocation;
    // scene.add(shelterLight);

    // 轮盘控制器

    const updateDrive = () => {
      const forward = this.setup.forward;
      const turn = this.setup.turn;
      let maxSteerVal = 0.05;
      let maxForce = .15;
      let force = maxForce * forward;
      let steer = maxSteerVal * turn;
      if (forward !== 0) {
        target.translateZ(force);
        // clip2 && clip2.play();
        // clip1 && clip1.stop();
      } else {
        // clip2 && clip2.stop();
        // clip1 && clip1.play();
      }
      target.rotateY(steer);
    }

    // 第三人称视角
    const followCamera = new THREE.Object3D();
    followCamera.position.copy(camera.position);
    scene.add(followCamera);
    followCamera.parent = target;

    const updateCamera = () => {
      if (followCamera) {
        camera.position.lerp(followCamera.getWorldPosition(new THREE.Vector3()), 0.1);
        camera.lookAt(target.position.x, target.position.y + .5, target.position.z);
      }
    }

    // 动画
    // var clock = new THREE.Clock();
    var lastTime: any;
    var fixedTimeStep = 1.0 / 60.0;
    const animate = () => {
      updateCamera();
      updateDrive();
      // let delta = clock.getDelta();
      // mixers.map(x => x.update(delta));
      let now = Date.now();
      lastTime === undefined && (lastTime = now);
      let dt = (Date.now() - lastTime) / 1000.0;
      lastTime = now;
      world.step(fixedTimeStep, dt);
      cannonHelper.updateBodies(world);
      check && check();
      // stats && stats.update();
      renderer.render(scene, camera);
      requestAnimationFrame(animate);
    };
    animate();
    this.startGame();
  }

  resetGame = () => {
    // this.player.position.set(this.playPosition.x, this.playPosition.y, this.playPosition.z);
    this.camera.position.set(1, 1, -1);
    this.target.position.set(0, 0, 0);
    this.target.rotation.set(0, 0, 0);
    this.startGame();
  }

  startGame = () => {
    this.setState({
      showLoading : false,
      freeDiscover: false
    });
  }

  discover = () => {
    this.setState({
      freeDiscover: true,
    });
  }

  handlerMove = (forward: number, turn: number) => {
    this.setup.forward = forward;
    this.setup.turn = -turn;
  }

  render () {
    return (
      <div className={styles.container}>
        <canvas className={styles.webgl} ref={canvasRef => this.canvasRef = canvasRef}></canvas>
        <div className={styles.tool}>
          <button className={styles.reset_button} onClick={this.resetGame}>重置</button>
        </div>
        {this.state.showLoading ? (<div className={styles.loading}>
          <div className={styles.box}>
            <p className={styles.progress}>{this.state.loadingProcess} %</p>
            <p className={styles.description}><span>2545光年</span>之外的<span>开普勒1028星系</span>，有一颗色彩斑斓的宜居星球，星际移民必须穿戴<span>基地</span>发放的防辐射服才能生存。<span>阿狸</span>驾驶星际飞行器降临此地，快帮它在限定时间内<span>使用轮盘移动</span>找到<span>基地</span>获取防辐射服吧！</p>
          </div>
        </div>) : '' }
        <JoyStick onMove={this.handlerMove} />
      </div>
    )
  }
}